# 官方网站：http://www.vnpy.cn
import threading
import logging
import os
import sys
from PyQt5 import QtWidgets, QtCore
# make the example runnable without the need to install
from os.path import abspath, dirname
import multiprocessing

sys.path.insert(0, abspath(dirname(abspath(__file__)) + '/..'))
# import multiprocessing
# from CTPMarketType import *
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(os.path.split(rootPath)[0])
print(sys.path)
import qdarkstyle
import configparser
import ui.example_pyqt5_ui as example_ui
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import *
# CTP行情库
from vnctpmd import *
# CTP交易库
from vnctptd import *
# K线数据服务库
from vnklineservice import *
# 策略计算进程库
from StrategyProcess import *
import time
from threading import Thread

from PyQt5.QtCore import *

global ui
ui = example_ui.Ui_MainWindow()


class VNDEFTradingAccountField(Structure):
    _fields_ = [('BrokerID', c_char * 11),  # 经纪公司代码
                ('InvestorID', c_char * 13),  # 投资者代码
                ('Prebalance', c_double),  # 合约代码
                ('Current', c_double),  # 报单引用
                ('Available', c_double),  # 用户代码
                ('Rate', c_double),  # 报单价格条件
                ('Positionrate', c_double),  # 买卖方向
                ('TradingDay', c_char * 9)
                ]

# MyCTPMarket类继承自CTPMarket类
class MyStrategyMangement(object):
    # 多进程策略管理
    list_hwnd=[]
    def StartStrategyProcess(self, msg):
        print("-->创建策略进程: ", msg[0], msg[1])
        sp = StrategyProcess(msg[0])
        thidprocesshwnd = sp.GetProcessHwnd()
        print('进程句柄返回值： '+str(thidprocesshwnd))
        self.list_hwnd.append(thidprocesshwnd)
        return ("完成创建策略进程: " + msg[0])

    def CreatStrategyProcess(self):
        # 进程池，用于策略计算，将回调函数注册给C++ DLL，形成多个进程实例，在多进程下运行策略计算
        pool = multiprocessing.Pool(processes=4)
        result = []
        for i in range(4):
            msg = ['MA策略.py', i]
            result.append(pool.apply_async(self.StartStrategyProcess, (msg,)))

        # pool.close()
        # pool.join()
        for res in result:
            print("-->进程返回值：", res.get())

    def GetStrategyMode(self):
        try:
            # 实例化configParser对象
            config = configparser.ConfigParser()
            # read读取ini文件
            config.read('VNStrategyProcess.ini', encoding='utf-8')
            if config.getint('setting', 'mode') == 1:
                print("当前策略模式：单线程模式执行策略运算，仅支持.py策略文件")
            elif config.getint('setting', 'mode') == 2:
                print("当前策略模式：C++策略管理器，C++多进程模式执行策略运算，支持.py策略文件和.dll策略文件")
                self.CreatStrategyProcess()
        except Exception as e:
            print("GetStrangeMode Error:" + repr(e))


# MyCTPTrade类继承自CTPTrader类
class MyCTPTrade(vnctptd, QtCore.QThread):
    def updatetradestock(self, InstrumentID):
        tradestocklist = []
        for i in range(min(len(ui.Button_t), len(tradestocklist))):
            ui.Button_t[i].setText(str(tradestocklist[i]))
            if len(tradestocklist) > VN_MOUTHNUM:
                hstr = ''
                les = min(VN_MOUTHNUM, len(tradestocklist))
                for j in range(les):
                    if j < les - 1:
                        hstr = hstr + tradestocklist[i] + ','
                    else:
                        hstr = hstr + tradestocklist[i]
                # with open("historystock.ini", "w") as f:
                #    f.write(hstr)

    def __init__(self, _signal):
        self._signal = _signal
        super().__init__(_signal)

    # 登录回调
    def OnRspUserLogin(self, a):
        # print(a.contents.a1, a.contents.a2)
        print(u'交易登录成功OnRspUserLogin')
        log_todaytd('交易登录成功OnRspUserLogin')
        ui.SetBarTDState(3)

    # 退出登录回调
    def OnRspUserLogout(self, a):
        print(a.contents.a1, a.contents.a2)
        print(u'交易登出成功OnRspUserLogout')
        log_todaytd('交易登出成功OnRspUserLogout')

    # 建立连接回调
    def OnFrontConnected(self):
        print("连接交易服务器成功OnFrontConnected")
        log_todaytd('连接交易服务器成功OnFrontConnected')
        ui.SetBarTDState(2)

        '''
        if self.ReqUserLogin() == 0:
            log_todaytd('发送登录交易服务器请求成功')
        else:
            log_todaytd('发送登录交易服务器请求失败')
        '''

    # 断开连接回调
    def OnFrontDisconnected(self, a):
        print("断开与交易服务器连接OnFrontDisconnected")
        log_todaytd('断开与交易服务器连接OnFrontDisconnected')
        ui.SetBarTDState(1)


    # 请求查询投资者持仓响应
    def OnRspQryInvestorPosition(self, a):
        #print("请求查询投资者持仓响应OnRspQryInvestorPosition")
        update_position(a)

    # 账户资金回调
    def OnRspQryTradingAccount(self, a):
        print("账户资金回调OnRspQryTradingAccount")
        update_account(a)

    # 委托回报
    def OnRtnOrder(self, a):
        print("----------------------委托回报OnRtnOrder")
        update_order(a)
        # updatetradestock(a.contents.InstrumentID)

    # 成交回报
    def OnRtnTrade(self, a):
        print("--------------------成交回报OnRtnTrade")
        update_trader(a)

# MyCTPMarket类继承自CTPMarket类
class MyCTPMarket(vnctpmd, QtCore.QThread):
    global list_INE, list_CFFEX, list_SHFE, list_DCE, list_CZCE
    global dict_exchange, dict_instrument

    def __init__(self, _signal):
        self._signal = _signal
        super().__init__(_signal)



    def UpdateMainType(self, instrumentMain, instrumentName, exchange, jump):
        global tempdate
        returnvalue = 0
        savedate = time.strftime("%Y%m%d", time.localtime())
        tvs = (int(float(savedate) * 0.000001)) * 1000000
        tempdate = int((float(savedate) - float(tvs)) * 0.01)
        tj = 0
        for j in range(VN_MOUTHNUM):
            if exchange == 'INE':
                returnvalue = mounthyear4(tempdate, j)
                update_instrument(instrumentMain + str(returnvalue), instrumentName, exchange, jump)
                globalvar.md.SubscribeMarketData(instrumentMain + str(returnvalue))
                if j == 0:
                    if len(instrumentMain) > 0:
                        globalvar.set_list_INE(instrumentMain + ',' + instrumentName + ',' + exchange)
                globalvar.dict_exchange[instrumentMain + str(returnvalue)] = exchange + ',能源所'
                globalvar.dict_instrument[
                    instrumentMain + str(returnvalue)] = instrumentMain + ',' + instrumentName + ',' + exchange
            elif exchange == 'CFFEX':
                returnvalue = mounthyear4(tempdate, j)
                update_instrument(instrumentMain + str(returnvalue), instrumentName, exchange, jump)
                globalvar.md.SubscribeMarketData(instrumentMain + str(returnvalue))
                if j == 0:
                    if len(instrumentMain) > 0:
                        globalvar.set_list_CFFEX(instrumentMain + ',' + instrumentName + ',' + exchange)
                globalvar.dict_exchange[instrumentMain + str(returnvalue)] = exchange + ',中金所'
                globalvar.dict_instrument[
                    instrumentMain + str(returnvalue)] = instrumentMain + ',' + instrumentName + ',' + exchange
            elif exchange == 'SHFE':
                returnvalue = mounthyear4(tempdate, j)
                update_instrument(instrumentMain + str(returnvalue), instrumentName, exchange, jump)
                globalvar.md.SubscribeMarketData(instrumentMain + str(returnvalue))
                if j == 0:
                    if len(instrumentMain) > 0:
                        globalvar.set_list_SHFE(instrumentMain + ',' + instrumentName + ',' + exchange)
                globalvar.dict_exchange[instrumentMain + str(returnvalue)] = exchange + ',上期所'
                globalvar.dict_instrument[
                    instrumentMain + str(returnvalue)] = instrumentMain + ',' + instrumentName + ',' + exchange
            elif exchange == 'DCE':
                returnvalue = mounthyear4(tempdate, j)
                update_instrument(instrumentMain + str(returnvalue), instrumentName, exchange, jump)
                globalvar.md.SubscribeMarketData(instrumentMain + str(returnvalue))
                if j == 0:
                    if len(instrumentMain) > 0:
                        globalvar.set_list_DCE(instrumentMain + ',' + instrumentName + ',' + exchange)
                globalvar.dict_exchange[instrumentMain + str(returnvalue)] = exchange + ',大商所'
                globalvar.dict_instrument[
                    instrumentMain + str(returnvalue)] = instrumentMain + ',' + instrumentName + ',' + exchange
            elif exchange == 'CZCE':
                returnvalue = mounthyear3(tempdate, j)
                update_instrument(instrumentMain + str(returnvalue), instrumentName, exchange, jump)
                globalvar.md.SubscribeMarketData(instrumentMain + str(returnvalue))
                if j == 0:
                    if len(instrumentMain) > 0:
                        globalvar.set_list_CZCE(instrumentMain + ',' + instrumentName + ',' + exchange)
                globalvar.dict_exchange[instrumentMain + str(returnvalue)] = exchange + ',郑商所'
                globalvar.dict_instrument[
                    instrumentMain + str(returnvalue)] = instrumentMain + ',' + instrumentName + ',' + exchange
        return returnvalue

    #生成合约列表
    def generateinstrumentID(self):
        instrumentidlist = []
        with open('InstrumentID.ini', 'r') as f:
            for line in f:
                instrumentIDarr = line.strip('\n').split(',')
                instrumentidlist.append(list(line.strip('\n').split(',')))
                self.UpdateMainType(instrumentIDarr[1], instrumentIDarr[2], instrumentIDarr[3], instrumentIDarr[4])

        # globalvar.printlist()
        # print("输出list: " + globalvar.list_INE[-1])
        ui.callback_md_combox()

    #读取配置文件
    def readklineserversetting(self):
        try:
            global config
            config = configparser.ConfigParser()
            # -read读取ini文件
            config.read('global.ini', encoding='utf-8')
            #是否从K线服务器读取读取当日数据
            globalvar.klineserverstate = config.getint('setting', 'klineserverstate')
            if globalvar.klineserverstate == 0:
                ui.Button_KlineSource_RealTimeTick.setChecked(True)
                ui.Button_KlineSource_Server.setChecked(False)
            else:
                ui.Button_KlineSource_RealTimeTick.setChecked(False)
                ui.Button_KlineSource_Server.setChecked(True)

            #print('read %s %s %s' % (investor, password, appid))
            #self.Edit_brokerid.setText(brokeid)
            #self.Edit_investor.setText(investor)
            #self.Edit_password.setText(password)
            #self.Edit_APPID.setText(appid)
            #self.Edit_authcode.setText(authcode)
            #self.Edit_auserproductinfo.setText(userproductinfo)
        except Exception as e:
            print("readklineserversetting Error:" + repr(e))

    #读取股票图表访问历史列表
    def readhistorystock(self):
        with open('historystock.ini', 'r') as f:
            for line in f:
                historystocklist = line.strip('\n').split(',')
                for i in range(min(len(ui.Button_h), len(historystocklist))):
                    ui.Button_h[i].setText(str(historystocklist[i]))
                    if len(historystocklist) > VN_MOUTHNUM:
                        hstr = ''
                        les = min(VN_MOUTHNUM, len(historystocklist))
                        for j in range(les):
                            if j < les - 1:
                                hstr = hstr + historystocklist[j] + ','
                            else:
                                hstr = hstr + historystocklist[j]
                        with open("historystock.ini", "w") as f:
                            f.write(hstr)

    #读取自选股列表
    def readoptionalstock(self):
        with open('optionalstock.ini', 'r') as f:
            for line in f:
                optionalstocklist = line.strip('\n').split(',')
                for i in range(min(len(ui.Button_zx), len(optionalstocklist))):
                    ui.Button_zx[i].setText(str(optionalstocklist[i]))
                    if len(optionalstocklist) > VN_MOUTHNUM:
                        hstr = ''
                        les = min(VN_MOUTHNUM, len(optionalstocklist))
                        for j in range(les):
                            if j < les - 1:
                                hstr = hstr + optionalstocklist[j] + ','
                            else:
                                hstr = hstr + optionalstocklist[j]
                        with open("optionalstock.ini", "w") as f:
                            f.write(hstr)

    def updatehistorystockagain(self, instrument, historystocklist2):
        tempinstrument = instrument
        if tempinstrument.strip('0123456789') == instrument:
            return
        reagain = 0
        if instrument in historystocklist2:
            for i in range(len(historystocklist2)):
                print(historystocklist2)
                if str(historystocklist2[i]) == instrument:
                    historystocklist2.pop(i)
                    reagain = 1
                    break
        if reagain == 1:
            self.updatehistorystockagain(instrument, historystocklist2)
        else:
            historystocklist2.insert(0, instrument)
            hstr = ''
            les = len(historystocklist2)
            for i in range(les):
                if i < les - 1:
                    hstr = hstr + historystocklist2[i] + ','
                else:
                    hstr = hstr + historystocklist2[i]
            with open("historystock.ini", "w") as f:
                f.write(hstr)
        self.readhistorystock()

    def updatehistorystock(self, instrument):
        tempinstrument = instrument
        if tempinstrument.strip('0123456789') == instrument:
            return
        reagain = 0
        with open('historystock.ini', 'r') as f:
            for line in f:
                historystocklist = line.strip('\n').split(',')
                if instrument in historystocklist:
                    for i in range(len(historystocklist)):
                        if str(historystocklist[i]) == instrument:
                            historystocklist.pop(i)
                            reagain = 1
                            break
        if reagain == 1:
            self.updatehistorystockagain(instrument, historystocklist)
        else:
            historystocklist.insert(0, instrument)
            hstr = ''
            les = len(historystocklist)
            for i in range(les):
                if i < les - 1:
                    hstr = hstr + historystocklist[i] + ','
                else:
                    hstr = hstr + historystocklist[i]
            with open("historystock.ini", "w") as f:
                f.write(hstr)
        self.readhistorystock()

    def ReqUserLogin(self):
        pass

    '''
    #重载
    def KlineM1 (self):
        print("wdg")
        super().KlineM1()
    '''

    # import threading
    # global lock
    # lock = threading.Lock()
    # 行情回调
    # global iname
    # iname=''
    def OnRtnDepthMarketData(self, tickdata):
        update_depthMarketData(tickdata)

        # print(str(tickdata.contents.InstrumentID, encoding="utf-8")+' , ' +str(tickdata.contents.LastPrice) )
        strategymanager(tickdata)
        # 注意这里与_signal = pyqtSignal(str)中的类型相同
        self.signal_md_tick.emit([tickdata.contents.InstrumentID, tickdata.contents.LastPrice, tickdata.contents.Volume,
                                  tickdata.contents.TradingDay, tickdata.contents.UpdateTime,
                                  tickdata.contents.UpdateMillisec])

        globalvar.thistoday = int(tickdata.contents.TradingDay)


        # self.signal_md_tick.emit(str(a.contents.InstrumentID, encoding="utf-8") + "%.2f" % tickdata.contents.LastPrice)

        # pnum = globalvar.td.GetPositionNum()
        # print('持仓记录: '+str(pnum))

    # 合约订阅回调
    def OnRspSubMarketData(self, a):
        print(u'订阅合约成功OnRspSubMarketData' + a.contents.InstrumentID)
        log_todaymd('订阅合约成功OnRspSubMarketData' + a.contents.InstrumentID)

    # 合约订阅回调
    def OnRspUnSubMarketData(self, a):
        print(u'反订阅合约成功OnRspUnSubMarketData' + a.contents.InstrumentID)
        log_todaymd('反订阅合约成功OnRspUnSubMarketData' + a.contents.InstrumentID)

    # 登录回调
    def OnRspUserLogin(self, a):
        # print(a.contents.a1, a.contents.a2)
        print(u'行情登录成功OnRspUserLogin')
        log_todaymd('行情登录成功OnRspUserLogin')
        # self.SubscribeMarketData('rb2110')
        self.generateinstrumentID()
        self.readklineserversetting()
        self.readhistorystock()
        self.readoptionalstock()
        ui.Function_Buttonclickh1()
        ui.SetBarMDState(3)

    # 退出登录回调
    def OnRspUserLogout(self, a):
        # print(a.contents.a1, a.contents.a2)
        print(u'行情登出成功OnRspUserLogout')
        log_todaymd('行情登出成功OnRspUserLogout')

    # 建立连接回调
    def OnFrontConnected(self):
        print("连接行情服务器成功OnFrontConnected")
        log_todaymd('连接行情服务器成功OnFrontConnected')
        ui.SetBarMDState(2)

    # 断开连接回调
    def OnFrontDisconnected(self, a):
        print("断开与行情服务器连接OnFrontDisconnected")
        log_todaymd('断开与行情服务器连接OnFrontDisconnected')
        ui.SetBarMDState(1)


    def SubscribeMarketData(self, a):
        return vnctpmd(self.signal_md_tick).SubscribeMarketData(a)

    def InitMD(self):
        return vnctpmd(self.signal_md_tick).InitMD()

    def ReqUserLogin(self):
        return vnctpmd(self.signal_md_tick).ReqUserLogin()

    def ReqUserLogout(self):
        return vnctpmd(self.signal_md_tick).ReqUserLogout()

#逻辑可能存在问题
class RegSpOnStrategyCalculate(Thread):
    def __init__(self, name, sp):
        super().__init__()
        self.name = name
        self.sp = sp

    def run(self):
        self.sp.VNRegOnStrategyCalculate()

# MyKlineService类继承自vnklineservice类
class MyKlineService(vnklineservice, QtCore.QThread):

    def __init__(self):
        super().__init__()

    # 合约订阅回调
    def OnKline(self, a):
        print(u'从服务器获取K线成功OnKline' + a.contents.InstrumentID)
        log_todaymd('从服务器获取K线成功OnKline' + a.contents.InstrumentID)

    def GetKline(self, InstrumentID, ID):
        vnklineservice().GetKline(InstrumentID.encode('gb2312'), ID)
        return 1


class RegTdThreadOnFrontConnected(Thread):
    def __init__(self, name, td):
        super().__init__()
        self.name = name
        self.td = td

    def run(self):
        self.td.VNRegOnFrontConnected()


class RegTdThreadOnFrontDisconnected(Thread):
    def __init__(self, name, td):
        super().__init__()
        self.name = name
        self.td = td

    def run(self):
        self.td.VNRegOnFrontDisconnected()


class RegTdThreadOnRspUserLogin(Thread):
    def __init__(self, name, td):
        super().__init__()
        self.name = name
        self.td = td

    def run(self):
        self.td.VNRegOnRspUserLogin()


class RegTdThreadOnRspUserLogout(Thread):
    def __init__(self, name, td):
        super().__init__()
        self.name = name
        self.td = td

    def run(self):
        self.td.VNRegOnRspUserLogout()


class RegTdThreadOnRspQryInvestorPosition(Thread):
    def __init__(self, name, td):
        super().__init__()
        self.name = name
        self.td = td

    def run(self):
        self.td.VNRegOnRspQryInvestorPosition()


class RegTdThreadOnRspQryTradingAccount(Thread):
    def __init__(self, name, td):
        super().__init__()
        self.name = name
        self.td = td

    def run(self):
        self.td.VNRegOnRspQryTradingAccount()


class RegTdThreadOnRtnOrder(Thread):
    def __init__(self, name, td):
        super().__init__()
        self.name = name
        self.td = td

    def run(self):
        self.td.VNRegOnRtnOrder()


class RegTdThreadOnRtnTrade(Thread):
    def __init__(self, name, td):
        super().__init__()
        self.name = name
        self.td = td

    def run(self):
        self.td.VNRegOnRtnTrade()


# ---------------------------------------
class RegMdThreadOnFrontConnected(Thread):
    def __init__(self, name, md):
        super().__init__()
        self.name = name
        self.md = md

    def run(self):
        self.md.VNRegOnFrontConnected()


class RegMdThreadOnFrontDisconnected(Thread):
    def __init__(self, name, md):
        super().__init__()
        self.name = name
        self.md = md

    def run(self):
        self.md.VNRegOnFrontDisconnected()


# RegThreadTdOnRspUserLogin
class RegMdThreadOnRspUserLogin(Thread):
    def __init__(self, name, md):
        super().__init__()
        self.name = name
        self.md = md

    def run(self):
        self.md.VNRegOnRspUserLogin()


# RegThreadTdOnRspUserLogin
class RegMdThreadOnRspUserLogout(Thread):
    def __init__(self, name, md):
        super().__init__()
        self.name = name
        self.md = md

    def run(self):
        self.md.VNRegOnRspUserLogout()


class RegMdThreadOnRtnDepthMarketData(Thread):
    def __init__(self, name, md):
        super().__init__()
        self.name = name
        self.md = md

    def run(self):
        self.md.VNRegOnRtnDepthMarketData()


class RegMdThreadOnRspSubMarketData(Thread):
    def __init__(self, name, md):
        super().__init__()
        self.name = name
        self.md = md

    def run(self):
        self.md.VNRegOnRspSubMarketData()


class RegMdThreadOnRspUnSubMarketData(Thread):
    def __init__(self, name, md):
        super().__init__()
        self.name = name
        self.md = md

    def run(self):
        self.md.VNRegOnRspUnSubMarketData()

class RegMdThreadOnStrategyCalculate(Thread):
    def __init__(self, name, md,list_hwnd):
        super().__init__()
        self.name = name
        self.md = md
        self.list_hwnd = list_hwnd

    def run(self):
        for k in self.list_hwnd:
            self.md.VNRegOnStrategyCalculate(k)

dict_position = {}
dict_order = {}
dict_trader = {}


def update_order(a):
    row_cnt = ui.table_order.rowCount()
    thiskey = str(a.contents.InstrumentID)
    if a.contents.InstrumentID == '':
        return
    if thiskey in dict_order:
        thisrowid = row_cnt
        pass
    else:
        print("y: " + thiskey)
        dict_order[thiskey] = row_cnt
        ui.table_order.insertRow(row_cnt)  # 尾部插入一行新行表格
        thisrowid = row_cnt
    column_cnt = ui.table_order.columnCount()  # 本地报单编号
    item = QTableWidgetItem(str(a.contents.OrderLocalID, encoding="utf-8"))
    ui.table_order.setItem(thisrowid, 0, item)
    item = QTableWidgetItem(str(a.contents.InstrumentID, encoding="utf-8"))
    ui.table_order.setItem(thisrowid, 1, item)
    if a.contents.Direction == '0':
        item = QTableWidgetItem('买')
    else:
        item = QTableWidgetItem('卖')
    ui.table_order.setItem(thisrowid, 2, item)
    item = QTableWidgetItem(str(a.contents.CombOffsetFlag, encoding="utf-8"))  # 开平
    ui.table_order.setItem(thisrowid, 3, item)
    item = QTableWidgetItem(str(a.contents.OrderStatus, encoding="utf-8"))  # 报单状态
    ui.table_order.setItem(thisrowid, 4, item)
    item = QTableWidgetItem("%d" % a.contents.VolumeTotalOriginal)  # 报单手数
    ui.table_order.setItem(thisrowid, 5, item)
    item = QTableWidgetItem("%d" % a.contents.VolumeTraded)  # 成交手数
    ui.table_order.setItem(thisrowid, 6, item)


def update_trader(a):
    row_cnt = ui.table_trade.rowCount()
    thiskey = str(a.contents.InstrumentID)
    if a.contents.InstrumentID == '':
        return
    if thiskey in dict_trader:
        thisrowid = row_cnt
        pass
    else:
        print("y: " + thiskey)
        dict_trader[thiskey] = row_cnt
        ui.table_trade.insertRow(row_cnt)  # 尾部插入一行新行表格
        thisrowid = row_cnt

    # column_cnt = ui.table_trade.columnCount()  # 返回当前列数
    item = QTableWidgetItem(str(a.contents.InstrumentID, encoding="utf-8"))
    ui.table_trade.setItem(thisrowid, 0, item)

    item = QTableWidgetItem(str(a.contents.TradeID, encoding="utf-8"))  # 成交编号
    ui.table_trade.setItem(thisrowid, 1, item)

    item = QTableWidgetItem(str(a.contents.OrderSysID, encoding="utf-8"))  # 报单编号
    ui.table_trade.setItem(thisrowid, 2, item)

    item = QTableWidgetItem(str(a.contents.InstrumentID, encoding="utf-8"))  # 合约
    ui.table_trade.setItem(thisrowid, 3, item)

    if a.contents.PosiDirection == b'1':
        item = QTableWidgetItem('净')
    elif a.contents.PosiDirection == b'2':
        item = QTableWidgetItem('买')
    elif a.contents.PosiDirection == b'3':
        item = QTableWidgetItem('卖')
    ui.table_trade.setItem(thisrowid, 4, item)

    item = QTableWidgetItem(str(a.contents.OffsetFlag, encoding="utf-8"))  # 开平
    ui.table_trade.setItem(thisrowid, 5, item)

    item = QTableWidgetItem(str(a.contents.Price, encoding="utf-8"))  # 成交价格
    ui.table_trade.setItem(thisrowid, 6, item)

    item = QTableWidgetItem(str(a.contents.Volume))  # 委托手数
    ui.table_trade.setItem(thisrowid, 7, item)






global tablepositonnum
tablepositonnum = 0


# 更新持仓表格
def update_addposition(a):
    row_cnt = ui.table_position.rowCount()
    thiskey = str(a.contents.InstrumentID)
    if a.contents.InstrumentID == '':
        return
    # 过滤平仓记录，不过滤仓位为0也会显示
    # 买平 1手 ，数据如下显示
    # 买卖，总持仓，可平量，持仓成本，持仓盈亏
    # 卖 ，0，    1，    0，       0
    if a.contents.UseMargin < 1e-7:
        return
    if thiskey in dict_position:
        thisrowid = row_cnt
        pass
    else:
        dict_position[thiskey] = row_cnt
        ui.table_position.insertRow(row_cnt)  # 尾部插入一行新行表格
        thisrowid = row_cnt

    column_cnt = ui.table_position.columnCount()  # 返回当前列数
    item = QTableWidgetItem(str(a.contents.InstrumentID, encoding="utf-8"))
    # md.SubscribeMarketData(a.contents.InstrumentID)
    ui.table_position.setItem(thisrowid, 0, item)
    # print('PosiDirection: '+ str(a.contents.PosiDirection, encoding="utf-8"))
    # 净
    # define THOST_FTDC_PD_Net '1'
    # 多头
    # define THOST_FTDC_PD_Long '2'
    # 空头
    # define THOST_FTDC_PD_Short '3'
    # item = QTableWidgetItem(str(a.contents.PosiDirection, encoding="utf-8"))
    if a.contents.PosiDirection == b'1':
        item = QTableWidgetItem('净')
    elif a.contents.PosiDirection == b'2':
        item = QTableWidgetItem('买')
    elif a.contents.PosiDirection == b'3':
        item = QTableWidgetItem('卖')
    ui.table_position.setItem(thisrowid, 1, item)
    item = QTableWidgetItem(str(a.contents.Position))  # 持仓
    ui.table_position.setItem(thisrowid, 2, item)
    item = QTableWidgetItem(str(a.contents.OpenVolume))  # 今仓
    ui.table_position.setItem(thisrowid, 3, item)
    item = QTableWidgetItem(str(a.contents.Position - a.contents.CloseVolume))  # 可平仓
    ui.table_position.setItem(thisrowid, 4, item)
    item = QTableWidgetItem("%.2f" % a.contents.UseMargin)  # 保证金
    ui.table_position.setItem(thisrowid, 5, item)
    item = QTableWidgetItem("%.2f" % a.contents.PositionCost)  # 持仓成本
    ui.table_position.setItem(thisrowid, 6, item)
    item = QTableWidgetItem("%.2f" % a.contents.PositionProfit)  # 持仓盈亏
    ui.table_position.setItem(thisrowid, 7, item)

    '''
    ui.Trade_CancelBtn  = QtWidgets.QPushButton('双击人工平仓')
    ui.Trade_CancelBtn.setFlat(True)
    ui.Trade_CancelBtn.setStyleSheet('background-color:#ff0000;');
    # searchBtn.setDown(True)
    ui.Trade_CancelBtn.setStyleSheet('QPushButton{margin:3px}')
    ui.table_position.setCellWidget(thisrowid, 6, ui.Trade_CancelBtn)
    '''


def update_position(a):
    # 检查表格记录数和C++底层数据是否一致，如果不一致，直接从底层CPP变量读取记录，否则仅增加一条记录
    global tablepositonnum
    try:
        if globalvar.td:
            pnum = globalvar.td.GetPositionNum()
            # print('持仓记录数a: ' + str(pnum))
            if tablepositonnum < pnum:
                for j in range(pnum):
                    returnvalue = globalvar.td.GetPosition(j)
                    # print(returnvalue.contents.InstrumentID, returnvalue.contents.PosiDirection)
                    update_addposition(returnvalue)
            update_addposition(a)
            # print('add: ' + str(a.contents.InstrumentID, encoding="utf-8"),str(a.contents.PosiDirection, encoding="utf-8"))
            tablepositonnum = tablepositonnum + 1

    except Exception as e:
        print("update_position Error:" + repr(e))


# 更新交易记录表格
global tableontradenum
tableontradenum = 0


def update_addontrade(a):
    row_cnt = ui.table_trade.rowCount()
    thiskey = str(a.contents.InstrumentID)
    if a.contents.InstrumentID == '':
        return
    if a.contents.UseMargin < 1e-7:
        return
    if thiskey in dict_position:
        thisrowid = row_cnt
        pass
    else:
        dict_position[thiskey] = row_cnt
        ui.table_trade.insertRow(row_cnt)  # 尾部插入一行新行表格
        thisrowid = row_cnt
    column_cnt = ui.table_trade.columnCount()  # 返回当前列数
    item = QTableWidgetItem(str(a.contents.InstrumentID, encoding="utf-8"))
    # md.SubscribeMarketData(a.contents.InstrumentID)
    ui.table_trade.setItem(thisrowid, 0, item)

    item = QTableWidgetItem(str(a.contents.TradeID, encoding="utf-8"))  # 成交编号
    ui.table_trade.setItem(thisrowid, 1, item)

    item = QTableWidgetItem(str(a.contents.OrderSysID, encoding="utf-8"))  # 报单编号
    ui.table_trade.setItem(thisrowid, 2, item)

    item = QTableWidgetItem(str(a.contents.InstrumentID, encoding="utf-8"))  # 合约
    ui.table_trade.setItem(thisrowid, 3, item)

    if a.contents.PosiDirection == b'1':
        item = QTableWidgetItem('净')
    elif a.contents.PosiDirection == b'2':
        item = QTableWidgetItem('买')
    elif a.contents.PosiDirection == b'3':
        item = QTableWidgetItem('卖')
    ui.table_trade.setItem(thisrowid, 4, item)

    item = QTableWidgetItem(str(a.contents.OffsetFlag, encoding="utf-8"))  # 开平
    ui.table_trade.setItem(thisrowid, 5, item)

    item = QTableWidgetItem(str(a.contents.Price, encoding="utf-8"))  # 成交价格
    ui.table_trade.setItem(thisrowid, 6, item)

    item = QTableWidgetItem(str(a.contents.Volume))  # 委托手数
    ui.table_trade.setItem(thisrowid, 7, item)








def update_ontrade(a):
    # 检查表格记录数和C++底层数据是否一致，如果不一致，直接从底层CPP变量读取记录，否则仅增加一条记录
    global tableontradenum
    try:
        if globalvar.td:
            pnum = globalvar.td.GetOnTradeNum()
            # print('交易记录数: ' + str(pnum))
            if tableontradenum < pnum:
                for j in range(pnum):
                    returnvalue = globalvar.td.GetOnTrade(j)
                    # print(returnvalue.contents.InstrumentID, returnvalue.contents.PosiDirection)
                    update_addontrade(returnvalue)
            update_addontrade(a)
            tableontradenum = tableontradenum + 1
    except Exception as e:
        print("update_ontrade Error:" + repr(e))


# 更新委托记录表格
global tableonordernum
tableonordernum = 0

def update_addonorder(a):
    row_cnt = ui.table_order.rowCount()
    thiskey = str(a.contents.InstrumentID)
    if a.contents.InstrumentID == '':
        return
    if a.contents.UseMargin < 1e-7:
        return
    if thiskey in dict_position:
        thisrowid = row_cnt
        pass
    else:
        dict_position[thiskey] = row_cnt
        ui.table_order.insertRow(row_cnt)  # 尾部插入一行新行表格
        thisrowid = row_cnt
    column_cnt = ui.table_order.columnCount()  # 返回当前列数

    item = QTableWidgetItem(str(a.contents.OrderSysID, encoding="utf-8"))
    ui.table_order.setItem(thisrowid, 0, item)

    item = QTableWidgetItem(str(a.contents.InstrumentID, encoding="utf-8"))
    # md.SubscribeMarketData(a.contents.InstrumentID)
    ui.table_order.setItem(thisrowid, 1, item)
    if a.contents.Direction == '0':
        item = QTableWidgetItem("多")  # 方向
    else:
        item = QTableWidgetItem("空")  # 方向
    ui.table_order.setItem(thisrowid, 2, item)
    if a.contents.CombOffsetFlag == '0':
        item = QTableWidgetItem("开")
    else:
        item = QTableWidgetItem("平")
    ui.table_order.setItem(thisrowid, 3, item)
    item = QTableWidgetItem(str(a.contents.OrderStatus))  # 报单状态
    ui.table_order.setItem(thisrowid, 4, item)
    item = QTableWidgetItem(str(a.contents.VolumeTotalOriginal))  # 数量
    ui.table_order.setItem(thisrowid, 5, item)
    item = QTableWidgetItem(str(a.contents.Position - a.contents.VolumeTraded))  # 今成交量
    ui.table_order.setItem(thisrowid, 6, item)
    item = QTableWidgetItem(str(a.contents.LimitPrice))  # 价格
    ui.table_order.setItem(thisrowid, 7, item)
    item = QTableWidgetItem("%s" % a.contents.InsertTime)  # 报单时间
    ui.table_order.setItem(thisrowid, 8, item)
    item = QTableWidgetItem("%s" % a.contents.ExchangeID)  # 交易所
    ui.table_order.setItem(thisrowid, 9, item)

def update_onorder(a):
    # 检查表格记录数和C++底层数据是否一致，如果不一致，直接从底层CPP变量读取记录，否则仅增加一条记录
    global tableonordernum
    try:
        if globalvar.td:
            pnum = globalvar.td.GetOnOrderNum()
            # print('委托记录数: ' + str(pnum))
            if tableonordernum < pnum:
                for j in range(pnum):
                    returnvalue = globalvar.td.GetOnOrder(j)
                    # print(returnvalue.contents.InstrumentID, returnvalue.contents.PosiDirection)
                    update_addonorder(returnvalue)
            update_addonorder(a)
            tableonordernum = tableonordernum + 1
    except Exception as e:
        print("update_onorder Error:" + repr(e))


def update3table():
    # 检查表格记录数和C++底层数据是否一致，如果不一致，直接从底层CPP变量读取记录，否则仅增加一条记录
    global tablepositonnum
    try:
        if globalvar.td:
            pnum = globalvar.td.GetPositionNum()
            print('持仓记录数c: ' + str(pnum))
            if tablepositonnum < pnum:
                for j in range(pnum):
                    returnvalue = globalvar.td.GetPosition(j)
                    print(returnvalue.contents.InstrumentID, returnvalue.contents.PosiDirection)
                    update_addposition(returnvalue)
            tablepositonnum = tablepositonnum + 1
    except Exception as e:
        print("update3table1 Error:" + repr(e))

    # 检查表格记录数和C++底层数据是否一致，如果不一致，直接从底层CPP变量读取记录，否则仅增加一条记录
    global tableontradenum
    try:
        if globalvar.td:
            pnum = globalvar.td.GetOnTradeNum()
            print('交易记录数c: ' + str(pnum))
            if tableontradenum < pnum:
                for j in range(pnum):
                    print('AAA')
                    returnvalue = globalvar.td.GetOnTrade(j)
                    print(returnvalue.contents.InstrumentID, str(returnvalue.contents.Volume))
                    update_addontrade(returnvalue)
            tableontradenum = tableontradenum + 1
    except Exception as e:
        print("update3table2 Error:" + repr(e))

    # 检查表格记录数和C++底层数据是否一致，如果不一致，直接从底层CPP变量读取记录，否则仅增加一条记录
    global tableonordernum
    try:
        if globalvar.td:
            pnum = globalvar.td.GetOnOrderNum()
            print('委托记录c: ' + str(pnum))
            if tableonordernum < pnum:
                for j in range(pnum):
                    returnvalue = globalvar.td.GetOnOrder(j)
                    print(returnvalue.contents.InstrumentID, returnvalue.contents.OrderRef)
                    update_addonorder(returnvalue)
            tableonordernum = tableonordernum + 1
    except Exception as e:
        print("update3table3 Error:" + repr(e))


instrumenttableid = 0


def update_instrument(instrumentID, instrumentName, exchange, jump):
    global instrumenttableid
    row_cnt = ui.table_instrument.rowCount()
    thiskey = str(instrumentID)
    if instrumentID == '':
        return
    if thiskey in dict_position:
        thisrowid = row_cnt
        pass
    else:
        dict_position[thiskey] = row_cnt
        ui.table_instrument.insertRow(row_cnt)  # 尾部插入一行新行表格
        thisrowid = row_cnt
    column_cnt = ui.table_instrument.columnCount()  # 返回当前列数
    # item = QTableWidgetItem(str(instrumentID, encoding="utf-8"))

    thisInstrumentID = VNInstrument()
    thisInstrumentID.InstrumentID = bytes(instrumentID, 'gb2312')

    instrumenttableid = instrumenttableid + 1
    item = QTableWidgetItem(str(instrumenttableid))
    ui.table_instrument.setItem(thisrowid, 0, item)
    item = QTableWidgetItem(str(instrumentName))
    ui.table_instrument.setItem(thisrowid, 1, item)
    item = QTableWidgetItem(instrumentID)
    ui.table_instrument.setItem(thisrowid, 2, item)
    item = QTableWidgetItem(str(exchange))
    ui.table_instrument.setItem(thisrowid, 3, item)
    item = QTableWidgetItem("%s" % jump)
    ui.table_instrument.setItem(thisrowid, 4, item)
    '''
    ui.Trade_CancelBtn  = QtWidgets.QPushButton('双击人工平仓')
    ui.Trade_CancelBtn.setFlat(True)
    ui.Trade_CancelBtn.setStyleSheet('background-color:#ff0000;');
    # searchBtn.setDown(True)
    ui.Trade_CancelBtn.setStyleSheet('QPushButton{margin:3px}')
    ui.table_position.setCellWidget(thisrowid, 6, ui.Trade_CancelBtn)
    '''


import os
# https://www.cnblogs.com/AmyHu/p/10654500.html
# https://blog.csdn.net/edward_zcl/article/details/88809212


import importlib


def dynamic_import(module):
    return importlib.import_module(module)


import globalvar

globalvar._init()

global dict_strategy, dict_strategyrun
# 策略文件名称
dict_strategy = ['MA策略', 'EMA策略', '3tick多空策略', '2根M1多空策略']
# 保存策略开启状态
dict_strategyrun = [1, 1, 1, 1]

readstrategyinstrumentIDstaste = 1


def readstrategyinstrumentID(strategyname):
    # 每次TICK都读取，可改为只读取一次
    global dict_strategyinstrument
    global readstrategyinstrumentIDstaste
    if readstrategyinstrumentIDstaste == 1:
        readstrategyinstrumentIDstaste = 0
        dict_tick = {}
        globalvar.dict_strategyinstrument[strategyname] = dict_tick
        with open('strategyfile\\' + strategyname + '.csv', 'r') as f:
            for line in f:
                print(strategyname + ' 策略对以下合约生效： ' + line)
                linelist = line.strip('\n').split(',')
                for k in iter(linelist):
                    globalvar.dict_strategyinstrument[strategyname][k] = k
                    # print('读取策略'+strategyname+' 交易合约：'+globalvar.dict_strategyinstrument[strategyname][line])


def strategymanager(marketdata):
    if globalvar.tradestate:
        # 定义跨模块全局变量
        globalvar.set_value('key1', 'Value1')
        globalvar.set_value('key2', 'Value2')
        '''
        module1 = dynamic_import('strategyfile.strategy1')
        module1.main(marketdata)
        module2 = dynamic_import('strategyfile.strategy2')
        module2.main(marketdata)
        return
        '''
        global dict_strategy, dict_strategyrun
        # 多个策略分别计算
        try:
            for k in dict_strategy:
                # print("strategyfile (%s) %s" % (ui.dict_strategy.index(k) + 1, k))
                print("(%s) %s" % (dict_strategy.index(k) + 1, k))
                if dict_strategyrun[int(dict_strategy.index(k))] == 1:
                    # print('允许运行该策略 %s' % k)
                    # 读取策略文件对应生效的合约文件，与策略文件同名，后缀名是.csv
                    readstrategyinstrumentID(k)
                    module = dynamic_import('strategyfile.' + k)
                    module.OnTick(marketdata, k)
        except Exception as e:
            print("strategymanager Error:" + repr(e))
    else:
        print("”启动策略自动交易按钮“未开启")


# 更新回测资金曲线
class UIUpdatebacktestingThread(threading.Thread):
    def __init__(self, newdata):
        super(UIUpdatebacktestingThread, self).__init__()
        self.newdata = newdata

    def run(self):
        ui.updatebacktestingUi(self.newdata)


# 更新K线图
class UIUpdateklineThread(threading.Thread):
    def __init__(self, InstrumentID):
        super(UIUpdateklineThread, self).__init__()
        self.InstrumentID = InstrumentID

    def run(self):
        ui.updateklineUi(self.InstrumentID)


# 更新分时图
class UIUpdatemarketThread(threading.Thread):
    def __init__(self, newdata):
        super(UIUpdatemarketThread, self).__init__()
        self.newdata = newdata

    def run(self):
        ui.updatemarketUi(self.newdata)


# 更新实时资金曲线
class UIUpdaterealtimecurveThread(threading.Thread):
    def __init__(self, newdata, tradeingday):
        super(UIUpdaterealtimecurveThread, self).__init__()
        self.newdata = newdata
        self.tradeingday = tradeingday

    def run(self):
        ui.updaterealtimecurveUi(self.newdata, self.tradeingday)


global UIUpdaterealtimecurveThreadjs
UIUpdaterealtimecurveThreadjs = -1


def update_account(a):
    # print(a.contents.TradingDay, str(a.contents.Available))
    row_cnt = ui.table_account.rowCount()
    item = QTableWidgetItem(str(a.contents.BrokerID, encoding="utf-8"))
    ui.table_account.setItem(0, 0, item)
    item = QTableWidgetItem(str(a.contents.InvestorID, encoding="utf-8"))
    ui.table_account.setItem(0, 1, item)
    item = QTableWidgetItem("%.2f" % a.contents.Prebalance)
    ui.table_account.setItem(0, 2, item)
    item = QTableWidgetItem("%.2f" % a.contents.Current)
    ui.table_account.setItem(0, 3, item)
    item = QTableWidgetItem(str(a.contents.Rate) + '%')
    ui.table_account.setItem(0, 4, item)
    item = QTableWidgetItem("%.2f" % a.contents.Available)
    ui.table_account.setItem(0, 5, item)
    item = QTableWidgetItem("%.2f" % a.contents.Positionrate + '%')
    ui.progressBar.setProperty("value", int(a.contents.Positionrate))
    ui.progressBar.setFormat("仓位：%p%")
    ui.table_account.setItem(0, 6, item)
    item = QTableWidgetItem("%.2f" % a.contents.Commission)
    ui.table_account.setItem(0, 7, item)
    item = QTableWidgetItem("%.2f" % a.contents.WithdrawQuota)
    ui.table_account.setItem(0, 8, item)
    tstr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime())
    tstr2 = time.strftime("%H%M%S ", time.localtime())
    item = QTableWidgetItem(tstr)
    ui.table_account.setItem(0, 9, item)
    # cur_dir = str(ui.QDir.currentPath()) + "/strategyfile"
    print(str(os.path.abspath(os.curdir)) + '\\curvedata\\' + str(a.contents.TradingDay, encoding="utf-8") + '.txt')
    with open(str(os.path.abspath(os.curdir)) + '\\curvedata\\' + str(a.contents.TradingDay, encoding="utf-8") + '.txt',
              "a") as f:
        f.write(str(a.contents.TradingDay, encoding="utf-8") + ',' + tstr2 + ',' + str(
            a.contents.Current) + '\n')  # 自带文件关闭功能，不需要再写f.close()
    global UIUpdaterealtimecurveThreadjs
    UIUpdaterealtimecurveThreadjs = UIUpdaterealtimecurveThreadjs + 1
    if UIUpdaterealtimecurveThreadjs >= 10 or UIUpdaterealtimecurveThreadjs == 0:
        UIUpdaterealtimecurveThreadjs = 0
        uithread = UIUpdaterealtimecurveThread(a.contents.Current, a.contents.TradingDay)
        uithread.start()


def update_depthMarketData(a):
    if globalvar.selectinstrumenid == a.contents.InstrumentID:
        # uimarketthread = UIUpdatemarketThread(a.contents.LastPrice)
        # uimarketthread.start()
        uiklinethread = UIUpdateklineThread(a.contents.InstrumentID)
        uiklinethread.start()


def log_todaytd(mystr):
    _translate = QtCore.QCoreApplication.translate
    item = QtWidgets.QListWidgetItem()
    ui.list_tdlog.addItem(item)
    item = ui.list_tdlog.item(ui.list_tdlog.count() - 1)
    tstr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime())
    item.setText(_translate("MainWindow", tstr + mystr))


def log_todaymd(mystr):
    _translate = QtCore.QCoreApplication.translate
    item = QtWidgets.QListWidgetItem()
    ui.list_mdlog.addItem(item)
    item = ui.list_mdlog.item(ui.list_mdlog.count() - 1)
    tstr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime())
    item.setText(_translate("MainWindow", tstr + mystr))


def function_td(td):
    RegTdThreadOnFrontConnected('OnFrontConnected', td).start()
    RegTdThreadOnFrontDisconnected('OnFrontDisconnected', td).start()
    RegTdThreadOnRspUserLogin('OnRspUserLogin', td).start()
    RegTdThreadOnRspUserLogout('OnRspUserLogout', td).start()
    RegTdThreadOnRspQryInvestorPosition('OnRspQryInvestorPosition', td).start()
    RegTdThreadOnRspQryTradingAccount('OnRspQryTradingAccount', td).start()
    RegTdThreadOnRtnOrder('OnRspQryInvestorPosition', td).start()
    RegTdThreadOnRtnTrade('OnRspQryInvestorPosition', td).start()

    time.sleep(1)
    td.InitTD()
    print("InitTD")
    # if td.InitTD() != 0:
    #    log_todaytd('初始化失败，请检查vnctptd.ini配置文件是否配置正确')
    # 调用交易接口元素，通过 “ 接口变量.元素（接口类内部定义的方法或变量） ” 形式调用
    # Login()，不需要参数，Login读取TD.ini的配置信息，并登录
    # 返回0， 表示登录成功，
    # 返回1， .ini错误
    # 返回2， 登录超时
    '''
    if td.ReqUserLogin() == 0:
        log_todaytd('发送登录交易服务器请求成功')
    else:
        log_todaytd('发送登录交易服务器请求失败')
    '''
    # 持仓数据在后台更新时，参数True为显示持仓状态，False为不显示持仓状态（仅对控制台有效）
    # td.SetShowPosition(True)

    # 注意simnow模拟盘的交易服务器不稳定，经常会出现查询不到的情况。实盘账户绑定的交易服务器无此问题。

    while 1:  # 死循环，反复执行
        '''
        # 如果值为-999999999（初始值），则表示尚未获得数据
        print(u'(1)动态权益：%0.02f' % td.QryBalance(True))
        print(u'(2)静态权益：%0.02f' % td.QryBalance(False))
        print(u'(3)可用资金：%0.02f' % td.QryAvailable())
        print(u'(4)zn1701今日空单持仓：%d' % td.QryPosition('rb1701', VN_POSITION_Sell_Today))
        print(u'(5)zn1701今日多单持仓：%d' % td.QryPosition('rb1701', VN_POSITION_Buy_Today))
        print(u'(6)zn1701非今日空单持仓：%d' % td.QryPosition('rb1701', VN_POSITION_Sell_History))
        print(u'(7)zn1701非今日多单持仓：%d' % td.QryPosition('rb1701', VN_POSITION_Buy_History))

        print('--------------------------------------------------------')
        '''
        time.sleep(3)  # sleep1秒，防止死循环导致CPU占有率过高，1即可，不宜过大，若过大会导致程序进程长时间无响应，丢失行情数据

    pass


global tempdata
thisdate = 0
global savedate


def mounthyear4(thisdate, add):
    year = (int)(thisdate * 0.01)
    mounth = thisdate - year * 100
    mounth = mounth + add
    if mounth > 12:
        mounth = mounth - 12
        year = year + 1
    thisdate = year * 100 + mounth
    return thisdate


def mounthyear3(thisdate, add):
    year = (int)(thisdate * 0.01)
    y = (int)(thisdate * 0.001)
    mounth = thisdate - year * 100
    mounth = mounth + add
    if mounth > 12:
        mounth = mounth - 12
        year = year + 1
    thisdate = year * 100 + mounth
    thisdate = thisdate - 1000 * y
    return thisdate


def function_md(md):
    # 注册异步回调函数线程（多线程回调，可绕过GIL锁）
    RegMdThreadOnFrontConnected('OnFrontConnected', md).start()
    RegMdThreadOnFrontDisconnected('OnFrontDisconnected', md).start()
    RegMdThreadOnRspUserLogin('OnRspUserLogin', md).start()
    RegMdThreadOnRspUserLogout('OnRspUserLogout', md).start()
    RegMdThreadOnRtnDepthMarketData('OnRtnDepthMarketData', md).start()
    RegMdThreadOnRspSubMarketData('OnRspSubMarketData', md).start()
    RegMdThreadOnRspUnSubMarketData('OnRspUnSubMarketData', md).start()

    time.sleep(1)
    result = md.InitMD()

    if result == 0:
        log_todaymd('行情接口配置文件读取成功')
    elif result == 1:
        log_todaymd('行情接口配置文件读取错误，请检查vnctpmd.ini是否存在')
        return
    elif result == 2:
        log_todaymd('行情接口配置文件读取错误，请检查vnctpmd.ini配置文件至少要配置一个行情IP地址')
        return

    '''
    #启动策略管理器
    #md.GetStrategyMode()
    if 0:
        sm = MyStrategyMangement()
        sm.GetStrategyMode()
        RegMdThreadOnStrategyCalculate('RegMdThreadOnStrategyCalculate', md,sm.list_hwnd).start()
    '''

    # generateinstrumentID()
    # md.RegisterFront()
    # Login()，不需要参数，Login读取QuickLibTD.ini的配置信息，并登录
    # 返回0， 表示登录成功，
    # 返回1， FutureTDAccount.ini错误
    # 返回2， 登录超时
    # 第一次是自动登录，退出登录后，如需再登陆，需添加以下登陆代码
    # 调用交易接口元素，通过 “ 接口变量.元素（接口类内部定义的方法或变量） ” 形式调用
    # Login()，不需要参数，Login读取QuickLibTD.ini的配置信息，并登录
    # 返回0， 表示登录成功，
    # 返回1， FutureTDAccount.ini错误
    # 返回2， 登录超时
    # print ('login: ', retLogin)

    # if md.Login() == 0:
    if md.ReqUserLogin() == 0:
        log_todaymd('发送登录行情服务器请求成功')
    else:
        log_todaymd('发送登录行情服务器请求失败')
    # 若登录成功，会触发 OnRspUserLogin 回调
    # 若登录失败，会触发 OnRspUserLogout 回调
    # 登录成功后，就可以执行情订阅等操作了，所以行情订阅放置在OnRspUserLogin()中执行

    # 设置拒绝接收行情服务器数据的时间，有时候（特别是模拟盘）在早晨6-8点会发送前一天的行情数据，若不拒收的话，会导致历史数据错误，本方法最多可以设置4个时间段进行拒收数据
    # md.SetRejectdataTime(0.0400, 0.0840, 0.1530, 0.2030, NULL, NULL, NULL, NULL);

    # main()函数内的以上部分代码只执行一次，以下while(1)循环内的代码，会一直循环执行，可在这个循环内需增加策略判断，达到下单条件即可下单

    # 判断当前时间是否在交易时间内，如果在返回真，则开始执行
    # if (IsStockTrade()):
    # 取消订阅
    # md.UnSubscribeMarketData(u'rb1810')
    # 退出登录
    # md.ReqUserLogout()
    # md.SubscribeMarketData(u'rb2110')
    # time.sleep(1)  # 系统休眠0.1秒

    # 重新订阅行情
    # md.Subcribe(u'rb1810')
    while 1:  # 死循环，反复执行
        # print(md.LastPrice("rb2110"))
        # 打印该品种在行情接口的变量LastPrice (最新价)
        # print(md.BidPrice1('rb2110'))
        # 打印该品种在行情接口的变量BidPrice
        time.sleep(30)  # 系统休眠


def OnTimer_checkstranger():
    # 检查策略修改
    timer = threading.Timer(10, OnTimer_checkstranger)
    timer.start()



def CheckInvestor():
    try:
        # 实例化configParser对象
        config = configparser.ConfigParser()
        # read读取ini文件
        config.read('vnctptd.ini', encoding='utf-8')
        if config.getint('setting', 'investor') == 188075:
            print(
                "vnctptd.ini默认配置了公用账户，请尽快改用自己的账户\n上期官方模拟账户注册（需工作日白天访问，其余时间网站关闭）：http://www.simnow.com.cn\n实盘账户开立（A级期货公司，手续费条件非常优惠）：http://www.kaihucn.cn")
    except Exception as e:
        print("CheckInvestor Error:" + repr(e))

def main():
    globalvar.currpath= os.path.abspath(os.path.dirname(__file__))
    logging.basicConfig(level=logging.DEBUG)
    app = QtWidgets.QApplication(sys.argv)
    window = QtWidgets.QMainWindow()
    # setup ui
    # ui = example_ui.Ui_MainWindow()
    ui.setupUi(window)

    # threading.Thread,
    class MDThread(QtCore.QThread):
        signal_md_tick = pyqtSignal(list)

        def __del__(self):
            self.wait()

        def __init__(self, tname):
            super(MDThread, self).__init__()
            self.tname = tname

        def run(self):
            time.sleep(3)
            globalvar.md = MyCTPMarket(self.signal_md_tick)
            globalvar.md.ui = ui
            function_md(globalvar.md)

    class TDThread(QtCore.QThread):
        signal_td_tick = pyqtSignal(str)

        def __del__(self):
            self.wait()

        def __init__(self, tname):
            super(TDThread, self).__init__()
            self.tname = tname

        def run(self):
            time.sleep(3)
            globalvar.td = MyCTPTrade(self.signal_td_tick)
            globalvar.td.ui = ui
            function_td(globalvar.td)

    #实时数据来自CTP API接口，但CTP不提供历史K线数据，历史K线数据服务是VNPY提供的服务，提供当日M1 K线数据
    #所以K线数据服务端必须闭源，这是选配模块，并不一定要使用，
    # 如果想屏蔽本模块（再Main函数删除以下2行
    # vk = KLineServiceThread('vk')
    # vk.start()）
    # 那么VNTrader会根据TICK实时生成M1周期K线
    # 回测数据模块、多日K线数据模块正在升级中
    class KLineServiceThread(QtCore.QThread):
        # signal_td_tick = pyqtSignal(str)

        def __del__(self):
            self.wait()

        def __init__(self, tname):
            super(KLineServiceThread, self).__init__()
            self.tname = tname

        def run(self):
            globalvar.vk = MyKlineService()
            globalvar.vk.ui = ui

    """
    ui.bt_delay_popup.addActions([
        ui.Navgiate1,
        ui.Navgiate1_C
    ])
    """
    ui.menu_b_popup.addActions([
        ui.Navgiate1,
        ui.Navgiate1_C
    ])
    """
    ui.bt_menu_button_popup.addActions([
        ui.Navgiate1,
        ui.Navgiate1_C
    ])
    """

    item = QtWidgets.QTableWidgetItem("1")
    item.setCheckState(QtCore.Qt.Unchecked)

    # 进程数量，应该不大于CPU逻辑核心数
    # processnum = multiprocessing.cpu_count()
    window.setWindowTitle("VNTrader (website: www.vnpy.cn 探索更真实的量化交易世界)")

    # tabify dock widgets to show bug #6
    window.tabifyDockWidget(ui.dockWidget1, ui.dockWidget2)
    ui.dockWidget1.raise_()

    # setup stylesheet
    print(qdarkstyle.load_stylesheet_pyqt5())
    app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())

    # auto quit after 2s when testing on travis-ci
    if "--travis" in sys.argv:
        QtCore.QTimer.singleShot(2000, app.exit)
    OnTimer_checkstranger()
    window.resize(1068, 700)
    window.setWindowIcon(QIcon('vnpy.ico'))
    window.showMaximized()
    window.show()
    vk = KLineServiceThread('vk')
    vk.start()
    tt = TDThread('tt')
    tt.signal_td_tick.connect(ui.callback_td_info)  # 进程连接回传到GUI的事件
    tt.start()
    tm = MDThread('tm')
    tm.signal_md_tick.connect(ui.callback_md_tick)  # 进程连接回传到GUI的事件
    tm.start()
    # timer = QTimer()  # 初始化一个定时器
    # timer.timeout.connect(update3table)
    # timer.start(1000)  # 设置计时间隔并启动
    CheckInvestor()
    app.exec_()
    os._exit(1)


if __name__ == "__main__":
    main()
